﻿using Datav.Design.Core;
using System.Collections.Concurrent;
using Zdap.Common.Extensions;


namespace Datav.Design
{
    /// <summary>
    ///
    /// </summary>
    public static class RecursiveExtensions
    {
        /// <summary>
        /// 递归处理子级对象（注:当前对象col不做处理）
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="col"></param>
        /// <param name="acqurieChildren">根据当前对象获取需要处理的子级对象集合</param>
        /// <param name="handler"> 处理器Action<ItemParent></param>
        public static void Recursive<T>(this T col, Func<T, IEnumerable<T>> acqurieChildren, Action<T, T> handler)   where T : class
        {
            ArgumentThrow.Null(acqurieChildren, "acqurieChildren");
            ArgumentThrow.Null(handler, "handler");
            if (col == null)
            {
                return;
            }

            var children = acqurieChildren(col);
            if (children != null && children.Any())
            {
                children.Foreach(item =>
                {
                    handler(item, col); 
                    Recursive(item, acqurieChildren, handler);
                });
            }
        }

        /// <summary>
        /// Recursively processes items with access to parent node
        /// </summary>
        /// <typeparam name="T">Item type</typeparam>
        /// <param name="root">Root item</param>
        /// <param name="getChildren">Function to get child items</param>
        /// <param name="action">Action to process each item (current, parent)</param>
        /// <param name="parent">Parent item (used internally for recursion)</param>
        public static void Recursive<T>(this T root, Func<T, IEnumerable<T>> getChildren, Action<T, T> action, T parent = null)
            where T : class
        {
            if (root == null || getChildren == null || action == null) return;
            action(root, parent);
            // Process children with current node as their parent
            var children = getChildren(root);
            if (children != null)
            {
                foreach (var child in children)
                {
                    child.Recursive(getChildren, action, root);
                }
            }
        }

        /// <summary>
        /// 递归处理子级对象（注:当前对象col不做处理）
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="col"></param>
        /// <param name="acqurieChildren">根据当前对象获取需要处理的子级对象集合</param>
        /// <param name="acquireResult">处理器Func<Item,Parent,Result></param>
        public static IEnumerable<TReturn> Recursive<T, TReturn>(this T col, Func<T, IEnumerable<T>> acqurieChildren, Func<T, T, TReturn> acquireResult)
        {
            ArgumentThrow.Null(acqurieChildren, "acqurieChildren");
            ArgumentThrow.Null(acquireResult, "acquireResult");
            if (col == null)
            {
                return Enumerable.Empty<TReturn>();
            }
            var list = new List<TReturn>();
            var children = acqurieChildren(col);
            if (children != null && children.Any())
            {
                children.Foreach(item =>
                {
                    list.Add(acquireResult(item, col));
                    list.AddRange(Recursive(item, acqurieChildren, acquireResult));
                });
            }

            return list.Where(item => item != null);
        }

        /// <summary>
        /// 对集合进行递归处理
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="col"></param>
        /// <param name="acqurieChildren"></param>
        /// <param name="handler"></param>

        public static void Recursive<T>(this IEnumerable<T> col, Func<T, IEnumerable<T>> acqurieChildren, Action<T> handler)
        {
            ArgumentThrow.Null(acqurieChildren, "acqurieChildren");
            ArgumentThrow.Null(handler, "handler");
            if (col == null || !col.Any())
            {
                return;
            }
            foreach (var item in col)
            {
                handler(item);
                Recursive(acqurieChildren(item), acqurieChildren, handler);
            }
        }

        /// <summary>
        /// 对集合进行递归处理
        /// </summary>
        /// <typeparam name="T">节点类型</typeparam>
        /// <typeparam name="TReturn">返回结果类型</typeparam>
        /// <param name="col">当前层级的节点集合</param>
        /// <param name="acquireChildren">获取子节点的方法（示例：node => node.Children）</param>
        /// <param name="acquireResult">处理节点的方法（示例：(current,parent) => 当前节点处理逻辑）</param>
        /// <returns></returns>
        /// <example> 
        /// <code>
        /// var node=rootNode.Recursive(node =>
        ///     {
        ///          return node.Children 
        ///     }, 
        ///     node => node.Children 
        ///  );
        ///  </code>
        /// </example>

        public static IEnumerable<TReturn> Recursive<T, TReturn>(this IEnumerable<T> col, Func<T, IEnumerable<T>> acqurieChildren, Func<T, TReturn> acquireResult)
        {
            ArgumentThrow.Null(acqurieChildren, "acqurieChildren");
            ArgumentThrow.Null(acquireResult, "acquireResult");
            if (col == null || !col.Any())
            {
                return Enumerable.Empty<TReturn>();
            }
            var list = new List<TReturn>();
            foreach (var item in col.Where(item => item != null))
            {
                list.Add(acquireResult(item));
                list.AddRange(Recursive(acqurieChildren(item), acqurieChildren, acquireResult));
            }
            return list;
        }

        /// <summary>
        /// 对集合进行递归处理（支持父子节点关联）
        /// </summary>
        public static IEnumerable<TReturn> Recursive<T, TReturn>(this IEnumerable<T> col, Func<T, IEnumerable<T>> acquireChildren, Func<T, T, TReturn> acquireResult) // 修改为接收当前节点和父节点
        {
            return Recursive(col, acquireChildren, acquireResult, default(T));
        }

        /// <summary>
        /// 添加父节点参数
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="TReturn"></typeparam>
        /// <param name="col"></param>
        /// <param name="acquireChildren"></param>
        /// <param name="acquireResult"></param>
        /// <param name="parent"></param>
        /// <returns></returns>
        private static IEnumerable<TReturn> Recursive<T, TReturn>(IEnumerable<T> col, Func<T, IEnumerable<T>> acquireChildren, Func<T, T, TReturn> acquireResult, T parent)
        {
            if (col == null || !col.Any())
            {
                return Enumerable.Empty<TReturn>();
            }
            var list = new List<TReturn>();
            foreach (var item in col.Where(x => x != null))
            {
                // 传入当前节点和父节点
                list.Add(acquireResult(item, parent));
                // 递归时传入当前节点作为子节点的父节点
                list.AddRange(Recursive(
                    acquireChildren(item),
                    acquireChildren,
                    acquireResult,
                    item)); // 传递当前节点作为父节点
            }

            return list;
        }

        /// <summary>
        /// 递归处理树形结构数据（支持父子节点关联）
        /// </summary>
        /// <typeparam name="T">节点类型</typeparam>
        /// <typeparam name="TReturn">返回结果类型</typeparam>
        /// <param name="col">当前层级的节点集合</param>
        /// <param name="acquireChildren">获取子节点的方法（示例：node => node.Children）</param>
        /// <param name="acquireResult">处理节点的方法（示例：(current,parent) => 当前节点处理逻辑）</param>
        /// <returns></returns>
        /// <example>
        /// 示例1：生成带层级缩进的名称
        /// <code>
        /// var tree = rootNode.Recursive(
        ///     x => x.Children,
        ///     (current, parent) => $"{new string(' ', level*2)}{current.Name}"
        /// );
        /// </code>
        /// 
        /// 示例2：构建完整路径（如"父节点,子节点,孙节点"）
        /// <code>
        /// var paths = nodes.Recursive(
        ///     x => x.Children,
        ///     (current, parent) => parent == null ? 
        ///         current.Name : 
        ///         $"{parent.FullPath},{current.Name}"
        /// );
        /// </code>
        /// </example>
        public static IEnumerable<TReturn> Recursive<T, TReturn>(this IEnumerable<T> col, Func<T, T, IEnumerable<T>> acquireChildren, Func<T, TReturn> acquireResult, T parent = default(T))
        {
            ArgumentThrow.Null(acquireChildren, "acquireChildren");
            ArgumentThrow.Null(acquireResult, "acquireResult");
            if (col == null || !col.Any())
            {
                return Enumerable.Empty<TReturn>();
            }
            var list = new List<TReturn>();
            foreach (var item in col.Where(item => item != null))
            {
                list.Add(acquireResult(item));
                // Pass the current item as parent to children
                list.AddRange(Recursive(
                    acquireChildren(item, parent),
                    acquireChildren,
                    acquireResult,
                    item));  // Current item becomes parent for next level
            }

            return list;
        }

        /// <summary>
        ///
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="TReturn"></typeparam>
        /// <param name="col"></param>
        /// <param name="acqurieChildren"></param>
        /// <param name="acquireResult"></param>
        /// <returns></returns>
        public static IEnumerable<TReturn> RecursiveParallel<T, TReturn>(this IEnumerable<T> col, Func<T, IEnumerable<T>> acqurieChildren, Func<T, TReturn> acquireResult)
        {
            ArgumentThrow.Null(acqurieChildren, nameof(acqurieChildren));
            ArgumentThrow.Null(acquireResult, nameof(acquireResult));

            if (col == null || !col.Any())
            {
                return Enumerable.Empty<TReturn>();
            }

            var result = new ConcurrentBag<TReturn>();

            Parallel.ForEach(col.Where(item => item != null), new ParallelOptions { MaxDegreeOfParallelism = 6 }, item =>
            {
                result.Add(acquireResult(item));

                foreach (var child in RecursiveParallel(acqurieChildren(item), acqurieChildren, acquireResult))
                {
                    result.Add(child);
                }
            });

            return result;
        }

        /// <summary>
        /// 集合转换树形结构数据返回
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        public static IEnumerable<T> BuildTree<T>(this IEnumerable<T> source) where T : TreeDto<T>
        {
            if (source == null || !source.Any())
                return source;

            var rootItems = source.Where(e => e.ParentId == 0 || e.ParentId == null).ToList();
            if (!rootItems.Any())
                return source;

            var datas2 = new List<T>();
            foreach (var parent in rootItems)
            {
                GetChildren(parent, source);
                datas2.Add(parent);
            }

            return datas2;
        }

        private static void GetChildren<T>(T parent, IEnumerable<T> datas) where T : TreeDto<T>
        {
            var children = datas.Where(e => e.ParentId == parent.Id).ToList();//根据父id查询父节点下所有的的子节点

            if (children.Count() == 0)
                return;

            foreach (var child in children)//递归查询子节点下的子节点
            {
                GetChildren(child, datas);
            }
            parent.Children = children;
        }

    }
}